
var error = (function ($) {

    var configMap = {
        ERROR_CLASS : "errorPut"
    };

    var 
    	iFormat,
    	handleError, displayError, resetError,
        getErrorMsg;

    /*
     * 处理ajax返回结果
     */
    handleError = function (result) {
    	
    	var errorCode = result.error.code;
    	if(errorCode == -101) {		//未登录
    		window.location.href = '/?forward=' + result.data.forward;
    		return;
    	} else if(errorCode == -359) {	//商家工具 未进行身份认证
    		window.location.href = '/merchant/merchantIndex.do?code=1&random=' + Math.random();
    		return;
    	} else if(errorCode == -203) {	//付款等操作的安全级别不够
    		window.location.href = '/?msgCode=MTAwMDA=&random=' + Math.random();
    		return;
    	}
    	
        var msg = getErrorMsg(result);
        if(errorCode == -19 || errorCode == -22 || errorCode == -31) {	//登陆密码、支付密码、短信验证码、谷歌验证码（提示次数）
    		msg += languageJson['comma'] + languageJson['coinOkYourHave'] + result.data.errorNum + languageJson['coinOkChance'];
    	} else if(errorCode == -243) {	//虚拟货币超出每日限额
    		if(result.data.authed == 1) {
    			return showConfirmDialog(result.data.limitAmount + 'CNY以上付款，需要您上传身份证', '', function() {
    				window.location.href = '/v1/user/showMerchantInfo.do';
    			});
    		} else if(result.data.authed == 2) {
    			msg = '您上传的身份证正在审核中，请耐心等待认证成功后再进行大于' + result.data.limitAmount + 'CNY的付款！';
    		} else {
    			msg = iFormat([result.data.currencyType, result.data.limitAmount], languageJson['error243']);
    		}
    	} else if(errorCode == -6011){
    		msg = iFormat([result.data.amount],languageJson['error6011']);
			return showConfirmDialog(msg);
    	}else if(errorCode == -246){
			return showConfirmDialog('48小时以内充值的CNY，不能用于BTC/LTC付款');
		}
        
        displayError(result.error.id, msg);
    };
    
    getErrorMsg = function (result) {

    	var errorKey = 'error' + Math.abs(result.error.code);
    	
    	var errorMsg = languageJson[errorKey];
    	if(errorMsg == null || errorMsg == '') {
    		errorMsg = languageJson['sysbusy'];
    	}
    	
    	return errorMsg;
    };

    /*
     * 显示错误信息
     */
    displayError = function (id, msg) {
    	
    	if(id == undefined || id == '') {
    		
    		showNoteInfo(msg, 3000);
    		
    	} else {
    		
    		$('#'+id).addClass(configMap.ERROR_CLASS);
            $('#'+id+'Error').text(msg).show();
    		
    	}
    	
    };
    
    iFormat = function(params, source) {
    	
    	if(params === undefined) {
    		return source;
    	}
    	
    	if ( params.constructor !== Array ) {
    		params = [ params ];
    	}
    	
    	return source.replace(/\{(\d+)}/g, function (match, i) {
    	        return params[i];
    	    });
    	
    }

    /*
     * 校验正确，重置错误信息
     */
    resetError = function (id) {
    	
        $('#'+id).removeClass(configMap.ERROR_CLASS);
        $('#'+id+'Error').text('').hide();
    };

    return {
        handleError: handleError,
        displayError: displayError,
        resetError: resetError,
        getErrorMsg: getErrorMsg
    };

})(jQuery);

var validateMethods = (function ($) {
	
	var methods, regexps, messages,
	
	configMap = {
        ERROR_CLASS: 'validate-error',
        VALIDATION_FLAG: 'data-validate'
    };
	
	/*************** 校验的规则和方法 start ************************/
    methods = {
    	//必填项
        required : function (value, param, id) {

            if ($('#'+id+'['+configMap.VALIDATION_FLAG+']').length <= 0) {
                return true;
            }
            return !param || value;
        },
        //邮箱地址
        email : function (value, param, id) {
        	
        	return !value || regexps.email.test(value);
        },
        //英文字母加空格
        pinyin : function (value, param, id) {
        	var reg = new RegExp("^[a-z|\\s|A-Z]{0,"+param+"}$");
        	return !value || reg.test(value);
        },
        //手机号
        phone : function (value, param, id) {
        	
        	if (!value) {
        		return true;
        	}
        	
        	if (param == '86' && !regexps.phone.test(value)) {
        		return false;
        	}
        	
        	return true;
        },
        //固定长度
        len : function (value, param, id) {

            return !value || value.length == param;
        },
        //字符串长度范围
        lengthrange : function (value, param, id) {

            return !value || (value.length >= param[0] && value.length <= param[1]);
        },
        //最大长度
        maxlength: function (value, param, id) {
        	
        	return !value || value.length <= param;
        },
        //最大unicode长度
        max_unicode_length : function (value, param, id) {
        	if(!value) return true;
        	var len = 0;
        	for(var i = 0; i < value.length; i++) {
        		var code = value.charCodeAt(i);
        		if (code >= 19968 && code <= 40959) {
        			len += 2; 
        		} else {
        			len += 1;
        		}
        	}
        	return len <= param;
        },
        //最小长度
        minlength: function (value, param, id) {
        	
        	return !value || value.length >= param;
        },
        //数字
        digit : function (value, param, id) {
        	
        	if (!value) {
        		return true;
        	}
        	
        	if (!regexps.digit.test(value)) {
        		return false;
        	}
        	
        	if (typeof param === 'number' && value.length !== param) {
        		return false;
        	}
        	
            return true;
        },
        //数值型（支持浮点数）
        float : function (value, param, id) {
        	
        	return !value || regexps.float.test(value);
        },
        //数值大小范围
        numberrange : function (value, param, id) {

            return !value || (value >= param[0] && value <= param[1]);
        },
        numberrange_id: function (value, param, id) {
        	
        	if(!value) {
        		return true;
        	}
        	
        	var range = getNumberRangeByType(param);
        	
        	return (value >= range[0] && value <= range[1]);
        },
        //最大数值
        maxnumber : function (value, param, id) {

            return !value || value <= param;
        },
        //最新小数值
        minnumber : function (value, param, id) {

            return !value || value >= param;
        },
        //浮点数的精度问题
        floatpoint : function (value, param, id) {

        	if(!value) {
        		return true;
        	} else {
        		value = value.trim();
        		var startIndex = value.indexOf('.');
        		if(startIndex > -1) {
        			var point = value.substring(startIndex + 1, value.length);
                	return point.length <= param;
        		} else {
        			return true;
        		}
        	}
        },
        floatpoint_id : function (value, param, id) {

        	if(!value) {
        		return true;
        	} else {
        		var bits = getFloatPointByType(param);
        		value = value.trim();
        		var startIndex = value.indexOf('.');
        		if(startIndex > -1) {
        			var point = value.substring(startIndex + 1, value.length);
                	return point.length <= bits;
        		} else {
        			return true;
        		}
        	}
        },
        //比特币地址
        btcaddress : function (value, param, id) {
        	//需要引用 /js/onchain/bitcoinjsok.js
        	if(!param || !value) {
        		return true;
        	} else {
	        	try{
	        		Bitcoin.address.fromBase58Check(value);
	        		return true;
	        	} catch(e){
	        		return false;
	        	}
           }
        },
        //url地址
        url : function (value, param, id) {

        	return !value || regexps.url.test(value);
        },
        //IPV4
        ipv4 : function (value, param, id) {

        	return !value || regexps.ipv4.test(value);
        },
        //IPV6
        ipv6 : function (value, param, id) {

        	return !value || regexps.ipv6.test(value);
        },
        //比较2次输入 要求相同
        equalTo : function (value, param, id) {
        	
        	var target = $('#' + param);
        	return !value || value === target.val();
        },
        //比较2次输入  要求不相同
        equalNoTo : function (value, param, id) {
        	
        	var target = $('#' + param);
        	return !value || value !== target.val();
        },
        
        value: function () {
        	return true;
        },
        
        nickname : function (value, param, id) {
        	var reg = /[,;]+/g;
        	return !value || !reg.test(value);
        },
        
        /*************功能性规则，返回true*******************/
        param : function (value, param, id) {
            return true;
        },
        
        keyup: function () {
        	return true;
        },
        
        bind: function () {
        	return true;
        },
        /************************************************/
        
        messageCode: function(value, param, id) {
        	return !value || (regexps.digit.test(value) && (value.length == 6));
        },
        
        googleCode: function(value, param, id) {
        	return !value || (regexps.digit.test(value) && (value.length == 6));
        }
        
    },
    
    //正则部分
    regexps = {
        digit: /^\d+$/,
        email: /^([a-zA-Z0-9_\-\.\+]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$/,
        float: /^-?(?:\d+|\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$/,
        url: /^(https?):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i,
        ipv4:/^(25[0-5]|2[0-4]\d|[01]?\d\d?)\.(25[0-5]|2[0-4]\d|[01]?\d\d?)\.(25[0-5]|2[0-4]\d|[01]?\d\d?)\.(25[0-5]|2[0-4]\d|[01]?\d\d?)$/i,
        ipv6:/^((([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}:[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){5}:([0-9A-Fa-f]{1,4}:)?[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){4}:([0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){3}:([0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){2}:([0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|(([0-9A-Fa-f]{1,4}:){0,5}:((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|(::([0-9A-Fa-f]{1,4}:){0,5}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|([0-9A-Fa-f]{1,4}::([0-9A-Fa-f]{1,4}:){0,5}[0-9A-Fa-f]{1,4})|(::([0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){1,7}:))$/i,
        phone: /^1[3|4|5|8|7][0-9]\d{8}$/,
        template: /\{(\d+)}/g
    },

    /*************** 校验的规则和方法 End **************************/

    /*************** 默认错误信息 Start ********************/
    
    messages = function(param, rule) {
    	
    	var msg = '';
    	
    	if(rule === 'numberrange_id') {
    		var range = getNumberRangeByType(param);
    		return format(range, languageJson['validate_common_numberrange']);
    	} else if(rule === 'floatpoint_id') {
    		var point = getFloatPointByType(param);
    		return format(point, languageJson['validate_common_floatpoint']);
    	} else if (rule === 'digit') {
    		if (typeof param === 'number') {
    			rule = 'digit_withlength';
    		}
    	}
    	
    	return format(param, languageJson['validate_common_' + rule]);
    },
    
    format = function(params, source) {
    	
    	if(params === undefined) {
    		return source;
    	}
    	
    	if ( params.constructor !== Array ) {
    		params = [ params ];
    	}
    	
    	/*$.each( params, function( i, n ) {
    		source = source.replace( new RegExp( "\\{" + i + "\\}", "g" ), function() {
    			return n;
    		});
    	});*/
    	
    	return source.replace(regexps.template, function (match, i) {
    	        return params[i];
    	    });
    	
    };
    
    getNumberRangeByType = function(type) {
    	
    	var balanceType, balanceUnit;
    	
    	if(Array.isArray(type)) {
    		balanceType = type[0];
    		balanceUnit = type[1];
    	} else {
    		balanceType = type;
    	}
    	
    	var range = [0.01, 999];	//default
    	
    	if(balanceType == 0) {	//BTC
    		if(balanceUnit == 1) {
    			range = [1, 1000000];
    		} else {
    			range = [0.001, 1000];
    		}
    	} else if(balanceType == 1) {	//LTC
    		if(balanceUnit == 1) {
    			range = [1, 20000000];
    		} else {
    			range = [0.001, 20000];
    		}
    	} else if(balanceType == 2) {	//CNY
    		range = [0.1, 999999];
    	} else if(balanceType == 3) {	//USD
    		range = [0.01, 99999];
    	}
    	
    	return range;
    }
    getFloatPointByType = function(type) {
    	
    	var balanceType, balanceUnit;
    	
    	if(Array.isArray(type)) {
    		balanceType = type[0];
    		balanceUnit = type[1];
    	} else {
    		balanceType = type;
    	}
    	
    	if(balanceType == 0 || balanceType == 1) {
    		if(balanceUnit == 1) {
    			return 5;
    		} else {
    			return 8;
    		}
    	} else {
    		return 2;
    	}
    }
    
    /***************默认错误信息 End**********************/
    
    /*
     * 返回公共方法
     */
    return {
        methods: methods,
        messages: messages
    };
    
})(jQuery);

var validator = function () {

    var
        validate, valid, addMethod, reset,

        validRule,
        submitHandler, getParams,
        
        init_button_handler, reset_button_handler, update_button_handler,

        getValueById, getElementById,

        methods = validateMethods.methods,
        messages = validateMethods.messages,
        custom_messages = {},

        handleError = error.handleError,
        displayError = error.displayError,
        resetError = error.resetError,

        savedConfig,

        configMap = {
            VALIDATION_FLAG: 'data-validate'
        },

        stateMap = {
            init: false,
            button_handler_init: false
        },

        jQueryMap = {
    		fields: {}
    	};


    /***************Utility Methods Start****************/

    getElementById = function (id) {
        return jQueryMap[id] || (jQueryMap[id] = $('#'+id));
    };

    getValueById = function (id) {
        var value = getElementById(id).val();
        return value && $.trim(value);
    };

    /***************Utility Methods End******************/
    
    
    /***************Private Helper Methods Start****************/
    
    init_button_handler = function () {
    	if (configMap.submit && (!stateMap.init || !stateMap.button_handler_init)) {
			jQueryMap.submit_btn.on('click', submitHandler).removeClass('btn3').addClass('btn');
    		stateMap.button_handler_init = true;
    	}
    };
    
    reset_button_handler = function () {
    	if (configMap.submit && (!stateMap.init || stateMap.button_handler_init)) {
    		stateMap.button_handler_init = false;
        	jQueryMap.submit_btn.off('click').removeClass('btn').addClass('btn3');
    	}
    };
    
    update_button_handler = function () {
    	
    	if (!configMap.submit) return;
    	
    	var bind_condition = configMap.submit.bind_condition;
    	if (typeof bind_condition === 'function') {
    		bind_condition = bind_condition();
    	}
    	
    	if (bind_condition) {
    		init_button_handler();
    	} else {
    		reset_button_handler();
    	}
    	
    };

    /*
     * 校验指定的元素
     */
    validRule = function (id, rule) {

        var flag = true;

        var value = rule.value ? rule.value(id) : getValueById(id);
        $.each(rule, function (name, param) {
        	
        	if (typeof param === 'object') {
        		if (param.depends && !param.depends()) {
        			return true;
        		}
        		if (param.param) {
        			param = param.param;
        		}
        	}

            if (typeof param === 'function') {
                param = param();
            }
            if (!methods[name](value, param, id)) {
                var msg =
                    (savedConfig.messages && savedConfig.messages[id] && savedConfig.messages[id][name]) || custom_messages[name] || messages;

                if (typeof msg === 'function') {
                    msg = msg(param, name);
                }

                var errorFun = (savedConfig.error && savedConfig.error[id]) || displayError;
                errorFun(id, msg);
                flag = false;

                return false;
            }

            return true;
        });

        if (flag) {
            resetError(id);
        } else {
            getElementById(id).attr(configMap.VALIDATION_FLAG, 'true');
        }
        return flag;
    };

    /*
     * 点击提交按钮的事件处理器
     */
    submitHandler = function () {

        //校验
        if (!valid()) {
            return false;
        }
        
        var oldVal = jQueryMap.submit_btn.val();
        jQueryMap.submit_btn.val(' ').removeClass('btn').addClass('waitBtn').off('click');
        
        //提交的url
        var url = configMap.submit.url;
        if (typeof url === 'function') {
        	url = url();
        }

        //读取参数
        var params = configMap.submit.params();

        //提交表单
        $.ajax({
        	url: url,
        	data: params,
        	dataType: 'json',
        	type: configMap.submit.method,
        	success: function (result) {
        		if (result) {
                    if (result.resultCode == 0) {
                    	if (configMap.submit.bind_on_change) {
                    		jQueryMap.submit_btn.val(oldVal).removeClass('waitBtn').addClass('btn3');
                    		reset_button_handler();
                    	} else {
                    		jQueryMap.submit_btn.val(oldVal).removeClass('waitBtn').addClass('btn').on('click', submitHandler);
                    	}
                    	
                        if (configMap.submit.success) {
                            configMap.submit.success(result);
                        }
                    } else {
                    	jQueryMap.submit_btn.val(oldVal).removeClass('waitBtn').addClass('btn').on('click', submitHandler);
                        configMap.submit.failed(result);
                    }
                } else {
                    console.log('oops...');
                }
        	}
        });
        
    };

    /*
     * 读取上传参数的方法
     */
    getParams = function () {

        var params = {};
        $.each(savedConfig.rules, function (id, rule) {

            var name = id;
            var get = getValueById;

            if (typeof rule === 'boolean') {
                if (!rule) return;
            } else if (typeof rule === 'function') {
                if (!rule()) return;
            } else {
                var type = (typeof rule.param);
                switch (type) {
                    case 'boolean':
                        if (!rule.param) return;
                        break;

                    case 'function':
                        if (!rule.param()) return;
                        break;

                    case 'object':
                        var included = !rule.param.included ? true 
                        		: (typeof rule.param.included === 'function')
		                            ? rule.param.included()
		                            : rule.param.included;

                        if (included === false) return;

                        name = !rule.param.name ? id 
                        		: (typeof rule.param.name === 'function')
		                            ? rule.param.name()
		                            : rule.param.name;

                        if (rule.param.value) {
                            get = rule.param.value;
                        }

                        break;
                }
            }

            params[name] = get(id);
        });
        return params;
    };
    
    /***************Private Helper Methods End******************/
    
    /***************Public Methods Start************************/

    /*
     * 为页面上的元素添加校验功能
     */
    validate = function (config) {

        if (!error || !validateMethods) {
            console.log('Dependency not matched!');
            return;
        }

        savedConfig = config;

        $.each(config.rules, function (id, rule) {
        	
            if (typeof rule === 'object') {

            	var jElem = getElementById(id);
                var domElem = jElem.get(0);
                
                if (domElem && domElem.nodeName === 'INPUT') {
                	
                	jQueryMap.fields[id] = jElem.val();
                	
                	jElem.on('blur', function () {
                        return validRule(id, rule);
                    })
                    .on('focus', function () {
                    	return validRule(id, rule);
                    })
                    .on('keyup', function (event) {
                    	
                    	if (event.keyCode == 13) {
                    		if (config.submit && stateMap.button_handler_init) {
                    			jQueryMap.submit_btn.trigger('click');
                    		}
                    		return true;
                    	}
                    	
                    	update_button_handler();
                    	
                    	if (rule.keyup === false) {
                    		return true;
                    	}

                        if (!this.hasAttribute(configMap.VALIDATION_FLAG)) {
                            return true;
                        }

                        return validRule(id, rule);
                    });
                	
                } else if (domElem && domElem.nodeName == 'SPAN') {
                	
                	if (jElem.hasClass('sel') || jElem.hasClass('unitSel') || jElem.hasClass('nationSel')) {
                		
                		jElem.on('selection_change', function () {
                			update_button_handler();
                		});
                		
                	} else if (jElem.hasClass('check') || jElem.hasClass('checked')) {
                		
                		jElem.on('checked_change', function () {
                			update_button_handler();
                		});
                		
                	}
                	
                }
                    
            }

        });

        if (config.submit) {

            //初始化configMap.submit
            configMap.submit = {
                params: getParams,
                failed: handleError,
                bind_on_change: false,
                bind_condition: true,
                method: 'POST'
            };

            $.extend(configMap.submit, config.submit);
            
            jQueryMap.submit_btn = $('#' + (config.submit.buttonId || 'submitBtn'));
            if (configMap.submit.bind_on_change) {
            	reset_button_handler();
            } else {
            	update_button_handler();
            }
            
        }

        stateMap.init = true;
    };

    /*
     * 手动校验用户输入
     */
    valid = function () {

        if (!stateMap.init) {
            console.log('Not initialized!');
            return false;
        }

        var flag = true;
        $.each(savedConfig.rules, function (id, rule) {
            if (typeof rule === 'object') {
                getElementById(id).attr(configMap.VALIDATION_FLAG, 'true');
                if (!validRule(id, rule)) {
                    flag = false;
                }
            }
        });
        return flag;
    };
    
    reset = function () {
    	
    	$.each(jQueryMap.fields, function (id, value) {
    		
    		resetError(id);
    		var jElem = getElementById(id).val(value);
    		
    		jElem.get(0).removeAttribute(configMap.VALIDATION_FLAG);
    		
    	});
    	
    };

    /*
     * 添加自定义校验方法
     */
    addMethod = function (name, fn, msg) {
        methods[name] = fn;
        custom_messages[name] = msg;
    };
    
    /***************Public Methods End**************************/

    
    /*
     * 返回公共方法
     */
    return {
        validate: validate,
        valid: valid,
        addMethod: addMethod,
        reset: reset
    };

};
